#include <stdlib.h>

#include "../image.h"
#include "../../util/macros.h"
#include "../../util/list.h"

static void _select_region(Image * Gray, Image * Sel, int x, int y, List * Roi, List * Contour);

void image_extract_region(Image * Gray, int x, int y, List ** Roi, List ** Contour) {

	Image * Sel;

	_verify(Gray);

	Sel = image_new(Gray->width, Gray->height, IMAGE_PALETTE_GRAY);

	if (Roi) if (*Roi == NULL) (*Roi) = list_new();
	if (Contour) if (*Contour == NULL) (*Contour) = list_new();

	_select_region(Gray, Sel, x, y, *Roi, *Contour);

	image_delete(Sel);

}

static void _select_region(Image * Gray, Image * Sel, int x, int y, List * Roi, List * Contour) {

	unsigned char * gray;
	unsigned char * sel;

	int rows;
	int columns;

	int i;

	rows = Gray->height;
	columns = Gray->width;


	if (x < 0 || x >= columns) return;
	if (y < 0 || y >= rows) return;

	gray = Gray->data;
	sel = Sel->data;

	i = y * columns + x;

	if (sel[i] > 0) {
		// pixel just visited
		return;
	}

	if (gray[i] == 0) {
		// not connected pixel. Contour pixel.

		//if (Contour) list_insert(Contour, point2d_new(x, y));

		//sel[i] = 100; // Mark border
		return;
	}

	sel[i] = 255;
	//if (Roi) list_insert(Roi, point2d_new(x, y));

	// left pixel
	_select_region(Gray, Sel, x - 1, y, Roi, Contour);

	// right pixel
	_select_region(Gray, Sel, x + 1, y, Roi, Contour);

	// top pixel
	_select_region(Gray, Sel, x, y - 1, Roi, Contour);

	// bottom pixel
	_select_region(Gray, Sel, x, y + 1, Roi, Contour);

	// top left
	_select_region(Gray, Sel, x - 1, y - 1, Roi, Contour);

	// top right
	_select_region(Gray, Sel, x + 1, y - 1, Roi, Contour);

	// bottom left
	_select_region(Gray, Sel, x - 1, y + 1, Roi, Contour);

	// bottom right
	_select_region(Gray, Sel, x + 1, y + 1, Roi, Contour);
}

void image_select8(Image Gray, int x, int y, Image ** Sel) {

	unsigned char * gray;
	unsigned char * sel;

	int rows;
	int columns;

	int i;

	rows = Gray.height;
	columns = Gray.width;

	if (x < 0 || x >= columns) return;
	if (y < 0 || y >= rows) return;

	_verify(Sel);
	if (Sel) if (*Sel == NULL) (*Sel) = image_new(Gray.width, Gray.height, IMAGE_PALETTE_GRAY);


	gray = Gray.data;
	sel = (*Sel)->data;

	i = y * columns + x;

	if (sel[i] > 0) {
		// pixel just visited
		return;
	}

	if (gray[i] == 0) {
		// not connected pixel
		//sel[i] = 100; // Mark border
		return;
	}

	sel[i] = 255;

	// left pixel
	image_select8(Gray, x - 1, y, Sel);

	// right pixel
	image_select8(Gray, x + 1, y, Sel);

	// top pixel
	image_select8(Gray, x, y - 1, Sel);

	// bottom pixel
	image_select8(Gray, x, y + 1, Sel);

	// top left
	image_select8(Gray, x - 1, y - 1, Sel);

	// top right
	image_select8(Gray, x + 1, y - 1, Sel);

	// bottom left
	image_select8(Gray, x - 1, y + 1, Sel);

	// bottom right
	image_select8(Gray, x + 1, y + 1, Sel);
}

void image_select4(Image Gray, int x, int y, Image ** Sel) {

	unsigned char * gray;
	unsigned char * sel;

	int rows;
	int columns;

	int i;

	rows = Gray.height;
	columns = Gray.width;

	if (x < 0 || x >= columns) return;
	if (y < 0 || y >= rows) return;

	_verify(Sel);
	if (Sel) if (*Sel == NULL) (*Sel) = image_new(Gray.width, Gray.height, IMAGE_PALETTE_GRAY);


	gray = Gray.data;
	sel = (*Sel)->data;

	i = y * columns + x;

	if (sel[i] > 0) {
		// pixel just visited
		return;
	}

	if (gray[i] == 0) {
		// not connected pixel
		//sel[i] = 100; // Mark border
		return;
	}



	sel[i] = 255;

	// left pixel
	image_select4(Gray, x - 1, y, Sel);

	// right pixel
	image_select4(Gray, x + 1, y, Sel);

	// top pixel
	image_select4(Gray, x, y - 1, Sel);

	// bottom pixel
	image_select4(Gray, x, y + 1, Sel);

}
